package com.literature.search.file.service.impl;

import com.literature.search.core.entity.redis.HotWord;
import com.literature.search.core.utils.RedisKeyUtils;
import com.literature.search.core.utils.sp.SpUserUtil;
import com.literature.search.file.service.RedisService;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName RedisServiceImpl
 * @Description TODO
 * @Author abin
 * @Date 2023/3/4 17:25
 * @Version 1.0
 */
@Service
public class RedisServiceImpl implements RedisService {

    public static final String HOT_WORD_COLLECTION_NAME = "hot_word";

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private MongoTemplate mongoTemplate;

    private final int MAX_HISTORY_KEYWORDS = 100;

    @Override
    public void insertSearchHistory(String userId, String value) {
        //阈值-历史最多10个
        long top  = 10;
        //生成key
        String key = RedisKeyUtils.getSearchHistoryKey(userId);
        // 拿到存入Redis里数据的唯一分值
        Double score = redisTemplate.opsForZSet().score(key, value);
        //检索是否有旧记录  1.无则插入记录值  2.有则删除 再次插入
        if(null != score){
            //删除旧的
            redisTemplate.opsForZSet().remove(key,value);
        }
        //加入新的记录，设置当前时间戳为分数score
        redisTemplate.opsForZSet().add(key,value,System.currentTimeMillis());
        //获取总记录数
        Long aLong = redisTemplate.opsForZSet().zCard(key);
        if(aLong > top){
            //移除多余记录
            redisTemplate.opsForZSet().removeRange(key,0,aLong-top-1);
        }
    }

    @Override
    public List<String> getSearchHistory() {
        List<String> searchHistoryList = new ArrayList<>();
        String userId = SpUserUtil.getCurrUser().getId();
        String key = RedisKeyUtils.getSearchHistoryKey(userId);
        long start = 1;             // 指定开始区间值
        long size  = 10;            // 指定长度区间值 （查询搜索历史记录最新的10条）
        Set<ZSetOperations.TypedTuple> scoreWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(key, start - 1, size - 1 );
        Iterator<ZSetOperations.TypedTuple> iterator = scoreWithScores.iterator();
        while (iterator.hasNext()){
            ZSetOperations.TypedTuple next = iterator.next();
            if ( next.getValue() != null ){
                searchHistoryList.add(next.getValue().toString());
            }
        }
        // 这里返回List给到前端
        return searchHistoryList;
    }

    @Override
    public void deleteSearchHistoryByValue(String value) {
        String userId = SpUserUtil.getCurrUser().getId();
        String key = RedisKeyUtils.getSearchHistoryKey(userId);
        redisTemplate.opsForZSet().remove(key,value);
    }

    @Override
    public void deleteAllSearchHistory() {
        String userId = SpUserUtil.getCurrUser().getId();
        String key = RedisKeyUtils.getSearchHistoryKey(userId);
        Long count = redisTemplate.opsForZSet().zCard(key);
        redisTemplate.opsForZSet().removeRange(key,0,count);
    }

    @Override
    public void countSearchHotWord(String keyword) {
        String sortedSetName = RedisKeyUtils.getSearchHotWordKey();
        double x = 1.0;
        redisTemplate.opsForZSet().incrementScore(sortedSetName, keyword, x);
    }

    @Override
    public List<String> getSearchHotWord() {
        List<String> searchHotWords = new ArrayList<>();
        String key = RedisKeyUtils.getSearchHotWordKey();
        long start = 1;             // 指定开始区间值
        long size  = 10;            // 指定长度区间值
        Set<ZSetOperations.TypedTuple> scoreWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(key, start - 1, size - 1 );
        Iterator<ZSetOperations.TypedTuple> iterator = scoreWithScores.iterator();
        while (iterator.hasNext()){
            ZSetOperations.TypedTuple next = iterator.next();
            if ( next.getValue() != null ){
                searchHotWords.add(next.getValue().toString());
            }
        }
        // 这里返回List给到前端
        return searchHotWords;
    }

    @Override
    public void SearchHotWord2DB(){
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String key = RedisKeyUtils.getSearchHotWordKey();
        long start = 1;             // 指定开始区间值
        long size  = 10;            // 指定长度区间值
        if (redisTemplate.hasKey(key)) {
            Set<ZSetOperations.TypedTuple> scoreWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(key, start - 1, size - 1);
            Iterator<ZSetOperations.TypedTuple> iterator = scoreWithScores.iterator();
            while (iterator.hasNext()) {
                ZSetOperations.TypedTuple next = iterator.next();
                if (next.getValue() != null) {
                    HotWord hotWord = new HotWord();
                    hotWord.setWord(next.getValue().toString());
                    hotWord.setCount(next.getScore().intValue());
                    hotWord.setDate(date);
                    mongoTemplate.insert(hotWord, HOT_WORD_COLLECTION_NAME);
                }
            }
            redisTemplate.opsForZSet().removeRange(key,0,-1);
        }
    }

    @Override
    public void countFileViews(String fileId) {
        String sortedSetName = RedisKeyUtils.getViewKey();
        double x = 1.0;
        redisTemplate.opsForZSet().incrementScore(sortedSetName, fileId, x);
    }

    @Override
    public void countFileDownloads(String fileId) {
        String sortedSetName = RedisKeyUtils.getDownloadKey();
        double x = 1.0;
        redisTemplate.opsForZSet().incrementScore(sortedSetName, fileId, x);
    }

    @Override
    public int getFileViewCount(String fileId){
        String sortedSetName = RedisKeyUtils.getViewKey();
        return redisTemplate.opsForZSet().score(sortedSetName,fileId).intValue();
    }

    @Override
    public int getFileDownloadCount(String fileId){
        String sortedSetName = RedisKeyUtils.getDownloadKey();
        return redisTemplate.opsForZSet().score(sortedSetName,fileId).intValue();
    }

    @Override
    public List<String> getFileViewList(){
        String sortedSetName = RedisKeyUtils.getViewKey();
        Set<String> fileIdSet = redisTemplate.opsForZSet().range(sortedSetName,0,-1);
        List<String> fileIdList = fileIdSet.stream().collect(Collectors.toList());
        return fileIdList;
    }

    @Override
    public List<String> getFileDownloadList(){
        String sortedSetName = RedisKeyUtils.getDownloadKey();
        Set<String> fileIdSet = redisTemplate.opsForZSet().range(sortedSetName,0,-1);
        List<String> fileIdList = fileIdSet.stream().collect(Collectors.toList());
        return fileIdList;
    }

    @Override
    public void deleteFileView(String fileId){
        String sortedSetName = RedisKeyUtils.getViewKey();
        redisTemplate.opsForZSet().remove(sortedSetName,fileId);
    }

    @Override
    public void deleteFileDownload(String fileId) {
        String sortedSetName = RedisKeyUtils.getDownloadKey();
        redisTemplate.opsForZSet().remove(sortedSetName,fileId);
    }

    @Override
    public void insertNeededUpdateFileId(String fileId) {
        String key = RedisKeyUtils.getUpdateFileKey();
        redisTemplate.opsForSet().add(key,fileId);
    }

    @Override
    public List<String> getNeededUpdateFileId() {
        String key = RedisKeyUtils.getUpdateFileKey();
        List<String> list = new ArrayList<>();
        if (redisTemplate.hasKey(key)) {
            Set<String> set = redisTemplate.opsForSet().members(key);
            list = set.stream().collect(Collectors.toList());
            return list;
        }
        return list;
    }

    @Override
    public void deleteNeededUpdateFileId(List<String> fileIds) {
        String key = RedisKeyUtils.getUpdateFileKey();
        redisTemplate.delete(key);
    }

    @Override
    public void countHotDocument(String fileId,Integer x) {
        String sortedSetName = RedisKeyUtils.getTopRankingKey();
        redisTemplate.opsForZSet().incrementScore(sortedSetName, fileId, x);
    }

    @Override
    public List<String> getHotDocument() {
        List<String> fileIds = new ArrayList<>();
        String key = RedisKeyUtils.getTopRankingKey();
        long start = 1;             // 指定开始区间值
        long size  = 10;            // 指定长度区间值
        Set<ZSetOperations.TypedTuple> scoreWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(key, start - 1, size - 1 );
        Iterator<ZSetOperations.TypedTuple> iterator = scoreWithScores.iterator();
        while (iterator.hasNext()){
            ZSetOperations.TypedTuple next = iterator.next();
            if ( next.getValue() != null ){
                fileIds.add(next.getValue().toString());
            }
        }
        return fileIds;
    }

    @Override
    public void deleteHotDocument(){
        String key = RedisKeyUtils.getTopRankingKey();
        redisTemplate.opsForZSet().removeRange(key,0,-1);
    }

    @Override
    public void setDocumentHistoryKeywordCount(String userId,Integer number){
        String key = RedisKeyUtils.getHistoryKeywordCounterKey(userId);
        Integer value = 0;
        if (redisTemplate.hasKey(key)){
            value = (Integer) redisTemplate.opsForValue().get(key);
            value = value + number;
            if (value < MAX_HISTORY_KEYWORDS){   // 最多存储100条历史搜索记录
                redisTemplate.opsForValue().set(key,value);
            }
            else {
                redisTemplate.opsForValue().set(key,0);
            }
        }else {
            redisTemplate.opsForValue().set(key,number);
        }
    }

    @Override
    public Integer getDocumentHistoryKeywordCount(String userId){
        String key = RedisKeyUtils.getHistoryKeywordCounterKey(userId);
        Integer integer = (Integer) redisTemplate.opsForValue().get(key);
        if (null == integer){
            setDocumentHistoryKeywordCount(userId,0);
            return 0;
        }
        return integer;
    }
}
